﻿using DreamWork.Model.ViewModel;
using DreamWork.Web.API.Infrastructure;
using IdentityModel.Client;
using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace DreamWork.Net
{
    public static class RestAPIClientExtensions
    {
        public static async Task<APIResult<TOut>> PutAsync<TIn, TOut>(this IRestAPIClient apiClient, TIn content)
        {
            return await apiClient.CallAPIAsync<TOut>(async (httpClient) =>
            {
                var stringContent = new StringContent(JsonConvert.SerializeObject(content), Encoding.UTF8, "application/json");
                return await httpClient.PutAsync($"{apiClient.Client.BaseAddress}{apiClient.APIPath}", stringContent);

            });
        }
        public static async Task<APIResult<TOut>> PostAsync<TIn, TOut>(this IRestAPIClient apiClient, TIn content)
        {
            return await apiClient.CallAPIAsync<TOut>(async (httpClient) =>
            {
                var stringContent = new StringContent(JsonConvert.SerializeObject(content), Encoding.UTF8, "application/json");
                return await httpClient.PostAsync($"{apiClient.Client.BaseAddress}{apiClient.APIPath}", stringContent);
                ///TODO 以下代码会出现serviceUnvilable的bug
                //return await httpClient.PostAsJsonAsync($"{apiClient.Client.BaseAddress}{apiClient.APIPath}", content);
            });
        }

        public static async Task<APIResult<TOut>> PostAsJsonAsync<TIn, TOut>(this IRestAPIClient apiClient, TIn content)
        {
            return await apiClient.CallAPIAsync<TOut>(async (httpClient) =>
            {
                return await httpClient.PostAsJsonAsync($"{apiClient.Client.BaseAddress}{apiClient.APIPath}", content);
            });
        }

        public static async Task<APIResult<T>> DeleteAsync<T>(this IRestAPIClient apiClient)
        {
            return await apiClient.CallAPIAsync<T>(async (httpClient) =>
            {
                return await httpClient.DeleteAsync($"{apiClient.Client.BaseAddress}{apiClient.APIPath}");
            });
        }
        public static async Task<APIResult<T>> GetAsync<T>(this IRestAPIClient apiClient)
        {
            return await apiClient.CallAPIAsync<T>(async (httpClient) =>
            {
                return await httpClient.GetAsync($"{apiClient.Client.BaseAddress}{apiClient.APIPath}");
            });
        }
        private static async Task<APIResult<T>> CallAPIAsync<T>(this IRestAPIClient apiClient, Func<HttpClient, Task<HttpResponseMessage>> operation)
        {
            var result = new APIResult<T>()
            {
                IsSuccess = false
            };
            if (apiClient.Options.UseAuthentication)
            {
                if (!string.IsNullOrEmpty(apiClient.Token))
                {
                    apiClient.Client.SetBearerToken(apiClient.Token.Replace("Bearer ",string.Empty));
                }
                else
                {
                    var discoveryClient = new DiscoveryClient(apiClient.Options.AuthenticationUrl);
                    discoveryClient.Policy.RequireHttps = false;
                    var disco = await discoveryClient.GetAsync();
                    if (disco.IsError)
                    {
                        result.IsSuccess = false;
                        result.Message = disco.Error;
                        return result;
                    }
                    var tokenClient = new TokenClient(disco.TokenEndpoint, apiClient.Options.ClientId, "secret");
                    var tokenResponse = await tokenClient.RequestClientCredentialsAsync("identity portalbasicapi portalbiapi identityresourcesapi earlywarningapi analyticsengineapi");

                    if (tokenResponse.IsError)
                    {
                        result.IsSuccess = false;
                        result.Message = tokenResponse.Error;
                        return result;
                    }
                    apiClient.Client.SetBearerToken(tokenResponse.AccessToken);
                }
            }

            //CacheControlHeaderValue cacheControl = new CacheControlHeaderValue
            //{
            //    Public = true,
            //    MaxAge = TimeSpan.FromMinutes(30),
            //};
            //apiClient.Client.DefaultRequestHeaders.CacheControl = cacheControl;

            try
            {
                var response = await operation(apiClient.Client);
                if (!response.IsSuccessStatusCode)
                {
                    result.ErrorCode = response.StatusCode.ToString();
                    result.Message = await response.Content.ReadAsAsync<string>();
                }
                else
                {
                    result.IsSuccess = true;
                    result.Content = await response.Content.ReadAsAsync<T>();
                }
            }
            catch (Exception ex)
            {
                result.IsSuccess = false;
                result.Message = $"API Call Exception:{apiClient.Client.BaseAddress}{apiClient.APIPath} {ex.Message}";
            }

            return result;
        }
    }
}
